; Part of NeoGS project, (c) NedoPC 2007-2008
;
; FPGA boot
;
;
	include	"cpld_ports.inc"

	relaxed on

		ORG	0
		phase	0

stack_top	equ	0x4080
recode_tbl	equ	0x4100

wbuf_addr	equ	0x6000 ;8kB buffer, 8kb boundary
wbuf_size	equ	0x2000
wbuf_hsize	equ	wbuf_size>>8
wbuf_mask	equ	1fffh
wbuf_hmask	equ	wbuf_mask>>8
wbuf_hend	equ	(wbuf_addr+wbuf_size)>>8



		di
		di
		jr	LOAD

		jp	(ix)
		jp	(ix)

		ret
		ret
		ret
		ret

		di
		halt
		di
		halt

DEF_ROM:
		di	;for default ROM load
		ld	sp,stack_top
		call	prepare
		jr	ROM

LOAD:
		ld	sp,stack_top ; use for stack first 128 bytes of RAM

		call	prepare


		in	a,(C_CRES)
		rlca
		jr	c,TRY_RAM
ROM:
		xor	a
		out	(C_MCFG),a
		ld	hl,config_data+0x8000
		jr	loadconfig

TRY_RAM:
                ld	a,0x81
                out	(C_MCFG),a ;ram at 8000-FFFF, page 1

		ld	hl,0x8000
		ld	b,(hl)
		inc	l
		ld	c,(hl)
		inc	l

		ld	a,b
		or	a
		jr	z,ROM  ;$0100 min length!
		cp	0x7F
		jr	nc,ROM ;$7EFF max length!

		add	hl,bc

		ld	d,(hl) ;precomputed CRC value
		dec	(hl)	;KILL CRC
		inc	hl
		ld	e,(hl)
		inc	(hl)	;KILL CRC
		push	de

		inc	bc
		inc	bc
		ld	hl,0x8000
		call	CRC16

		pop	hl
		or	a
		sbc	hl,de
		jr	nz,ROM ;if CRC failed

		ld	hl,0x8002

                ;; start configuration
loadconfig:
		ld	a,0x81
		out	(C_CRNCFG),a	;clear cold_reset flag
		call	configure

                ; end config, see is it correct
wait_init:
		in	a,(C_NSTCDON)
		sra	a
		jp	p,DEF_ROM
		jr	nc,wait_init

		; here CONF_DONE is released, nothing to do more (reboot takes place when INIT_DONE toggles)

		di
		halt



USE_BUFFER:	;hl - from
		;de - len (down to zero)
		;kills af,bc,de,hl

                ld	b,recode_tbl>>8
		jr	ub_entry

ub_loop:
		ld	c,(hl)
		inc	hl
		ld	a,(bc)
		out	(C_FPGADAT),a


		call	ready


		dec	de

ub_entry:	ld	a,d
		or	e
		jr	nz,ub_loop

		ret


prepare:
		;reset FPGA by pulling NCONFIG down
		xor	a
		out	(C_CRNCFG),a

		;switch ROM in 8000-FFFF, first 32k, then check it for CRC
		;xor	a
		out	(C_MCFG),a

		;calc and compare CRC of rom
		ld	hl,0x8000
		ld	bc,crc_is_here
		call	CRC16
		ld	a,(hl)
		inc	hl
		ld	l,(hl)
		ld	h,a
		or	a
		sbc	hl,de
		jr	nz,prepare

		call	mk_recode_tbl

		ld	a,1
		out	(C_CRNCFG),a ;release nconfig

wait_nstat:
                in	a,(C_NSTCDON) ;read nstatus, wait it to be 1
                rla
                jr	nc,wait_nstat

		ret


ready:

cfg_rdynbsy:	; wait for ready
		in	a,(C_FPGADAT)
		rla
		jr	nc,cfg_rdynbsy

		; restart if error during configuration
		in	a,(C_NSTCDON)
		rla
		jp	nc,DEF_ROM

		ret



mk_recode_tbl:
		ld	de,recode_tbl
mrt_loop:

		ld	a,e
		and	0b01001001 ; preserve d0,d3,d6
		ld	b,a

		ld	a,e
		and	0b10010000 ; d7 and d4
		rrca
		rrca
		rrca
		or	b
		ld	b,a ;01011011

		ld	a,e
		and	0b00000010 ; d1
		rlca
		or	b
		ld	b,a ;01011111

		ld	a,e
		and	0b00000100 ; d2
		rlca
		rlca
		rlca
		or	b
		ld	b,a ;01111111

		ld	a,e
		and	0b00100000 ; d5
		rlca
		rlca
		or	b ;11111111

		ld	(de),a

		inc	e
		jr	nz,mrt_loop

		ret

;; recode config data:

;    Z80     fpga
;     D0       D0 *
;     D1       D4
;     D2       D1
;     D3       D3 *
;     D4       D7
;     D5       D2
;     D6       D6 *
;     D7       D5



configure:
	ld	de,wbuf_addr

DEC40buf
        LD      A,0x80
        EX      AF,AF'
MS      LDI
	call	after_ldi
M0      LD      BC,0x2FF
M1      EX      AF,AF'
M1X     ADD     A,A
        JR      NZ,M2
        LD      A,(HL)
        INC     HL
        RLA
M2      RL      C
        JR      NC,M1X
        EX      AF,AF'
        DJNZ    X2
        LD      A,2
        SRA     C
        JR      C,N1
        INC     A
        INC     C
        JR      Z,N2
        LD      BC,0x33F
        JR      M1

X2      DJNZ    X3
        SRL     C
        JR      C,MS
        INC     B
        JR      M1
X6
        ADD     A,C
N2
        LD      BC,0x4FF
        JR      M1
N1
        INC     C
        JR      NZ,M4
        EX      AF,AF'
        INC     B
N5      RR      C
;;;;    RET     C
	jr	c,dec40end

        RL      B
        ADD     A,A
        JR      NZ,N6
        LD      A,(HL)
        INC     HL
        RLA
N6      JR      NC,N5
        EX      AF,AF'
        ADD     A,B
        LD      B,6
        JR      M1
X3
        DJNZ    X4
        LD      A,1
        JR      M3
X4      DJNZ    X5
        INC     C
        JR      NZ,M4
        LD      BC,0x51F
        JR      M1
X5
        DJNZ    X6
        LD      B,C
M4      LD      C,(HL)
        INC     HL
M3      DEC     B
        PUSH    HL
        LD      L,C
        LD      H,B
        ADD     HL,DE
        LD      C,A
        LD      B,0
;;;;    LDIR
	call	wrap_ldir
        POP     HL
        JR      M0
END_DEC40

dec40end:
		ex	de,hl
		ld	de,wbuf_addr
		or	a
		sbc	hl,de
		ex	de,hl
		jp	USE_BUFFER


after_ldi:	push	af
		ld	a,d
		cp	wbuf_hend
		jr	c,al_nothing
		push	hl

		ld	hl,wbuf_addr
		ld	de,0x2000
		call	USE_BUFFER

		ld	de,wbuf_addr
		pop	hl
al_nothing:
		pop	af
		ret


wrap_ldir:
		ld	a,h
		cp	wbuf_addr>>8
		jr	nc,wl_nohlwrap
		add	a,wbuf_hsize
		ld	h,a
wl_nohlwrap:
		ld	a,wbuf_hend-1
wl_ldiloop:
		ldi
		jp	po,after_ldi

		cp	d
		jr	c,wl_dewrap
		cp	h
		jr	nc,wl_ldiloop
;wl_hlwrap
		ld	h,wbuf_addr>>8
		jr	wl_ldiloop
wl_dewrap:
		push	bc
		call	after_ldi
		pop	bc
		jr	wl_nohlwrap




CRC16:	;calculates crc16-ccitt with initial value of CRC=$FFFF

	;INPUT:		HL - memptr
	;		BC  - byte count
	;OUTPUT:	DE - resulting crc value
	;		HL - ptr to byte after last processed
	;KILLS:		AF,BC,IX

		;algo: crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *(char *)buf++)&0x00FF];

		ld	a,c
		or	a
		jr	z,$+3
		inc	b

		ld	ixl,b
		ld	b,c


		ex	de,hl
		ld	hl,(crc16table&$FF00)+$FF	;high part of table, initial crc.lo
		ld	c,l				;initial crc.hi

c1_loop

;de - memptr; h - table>>8, c - crc.hi, l - crc.lo, b - counter

		ld	a,(de)
		inc	de
		xor	c
		ld	c,a	;c=index

		ld	a,l	;a=crc.lo
		ld	l,c	;hl=tab.hi
		xor	(hl)	;a=new crc.hi
		inc	h
		ld	l,(hl)	;l=new crc.lo
		dec	h
		ld	c,a

		djnz	c1_loop

		dec	ixl
		jr	nz,c1_loop


		ld	h,c
		ex	de,hl

		ret



		org	($+255)&0xFF00
crc16table:
	db	0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70
	db	0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1
	db	0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62
	db	0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3
	db	0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54
	db	0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5
	db	0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46
	db	0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7
	db	0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38
	db	0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9
	db	0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a
	db	0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab
	db	0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c
	db	0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d
	db	0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e
	db	0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f
	db	0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1
	db	0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60
	db	0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3
	db	0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72
	db	0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5
	db	0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44
	db	0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7
	db	0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56
	db	0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9
	db	0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28
	db	0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb
	db	0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a
	db	0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d
	db	0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c
	db	0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f
	db	0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e

	db	0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7
	db	0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef
	db	0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6
	db	0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde
	db	0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85
	db	0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d
	db	0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4
	db	0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc
	db	0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23
	db	0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b
	db	0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12
	db	0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a
	db	0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41
	db	0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49
	db	0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70
	db	0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78
	db	0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f
	db	0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67
	db	0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e
	db	0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56
	db	0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d
	db	0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05
	db	0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c
	db	0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34
	db	0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab
	db	0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3
	db	0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a
	db	0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92
	db	0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9
	db	0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1
	db	0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8
	db	0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0





config_data:
		binclude	"main.mlz"


crc_is_here:

